

#include "mcu_crc16.h"
#include "mcu_modbus_slaver.h"
#include  "mcu_clib.h"
#include "dda_server.h"
#include "dda_class.h"
  




extern  IReqProcessor* LocateReqServerAndMemberId(WORD ddaId, WORD* memberId,WORD* memberDataType);


#define MB_MEG2(a,b)		   ((uint16_t)a << 8) & 0xff00 | ((uint16_t)b & 0xff)
#define MB_MEG4(a,b,c,d)	((uint32_t)a << 24) & 0xff000000 | ( (uint32_t)b<< 16) & 0xff0000 | ( (uint32_t)c<< 8) & 0xff00 |  (uint32_t)d & 0xff
/*
  * 错误码
  */
enum ModbusErrCode
{
	MODBUS_ERR_CODE_SUCCESS = 0,
	MODBUS_ERR_CODE_ILLEGAL_FUNCTION_CODE = 1,//非法功能码
	MODBUS_ERR_CODE_ILLEGAL_DATA_ADDRESS = 2,//非法数据地址
	MODBUS_ERR_CODE_ILLEGAL_DATA_CONTENT = 3,//非法数据内容
	MODBUS_ERR_CODE_SUB_STATION_EQUIPMENT_ERROR = 4,//子站设备错误
	MODBUS_ERR_CODE_SUB_STATION_BUSY = 6,//子站忙
	MODBUS_ERR_CODE_CRC_CHECK_ERR = 7 //crc检查错误
};

/*
  * 功能码
  */
enum ModbusFunCode
{
	//读保持寄存器
	MODBUS_FUN_CODE_03 = 3,
	//写单个保持寄存器
	MODBUS_FUN_CODE_06 = 6,
	//写多个保持寄存器
	MODBUS_FUN_CODE_16 = 16,
	//RPC调用
	MODBUS_FUN_CODE_100 = 100
};


/*
 * 特殊地址
 */
enum ModbusSlaveAddr
{
	//广播
	MODBUS_SLAVE_ADDR_BROADCAST = 0,
	//发现
	MODBUS_SLAVE_ADDR_DISCOVER = 246,
	//通用
	MODBUS_SLAVE_ADDR_GENERAL = 247
};


McuModbusSlaver::McuModbusSlaver(McuCommDriver* pCommDriver, uint8_t slaveAddr,BOOL	isLeader,WORD teamCount) {
	m_slaveAddr = slaveAddr;
	m_isLeader = isLeader;
	m_teamCount = teamCount;
	m_pCommDriver = pCommDriver;
	m_reqNPack = new NPack();
	m_resNdata = new Ndata();
	m_pCxReturn = new CxReturn();
	m_returnData = new ReturnData(m_resNdata);
	m_byteLen = 0;

}

McuModbusSlaver::~McuModbusSlaver() {
	delete m_reqNPack;
	delete m_pCxReturn;
	delete m_resNdata;
	delete m_returnData;
}


uint8_t McuModbusSlaver::ReadOrWrite(int isRead, uint16_t ddaId, uint8_t* buf, uint16_t bufLen) {
	WORD	   memId = 0;
	WORD	   memDataType = 0;
	//找实例
	IReqProcessor* reqServer = LocateReqServerAndMemberId(ddaId, &memId,&memDataType);
	if (reqServer == NULL) {
		return 1;
	}
	WORD callId = isRead ? CALL_GetParam : CALL_SetParam;
	m_reqNPack->Reset();
	//读写第一个参数都是memId
	m_reqNPack->AppendWord(memId);
	//构造写参数
	if (!isRead) {
		Ndata nd1;
		ByteBuf2Ndata(buf, bufLen, &nd1,memDataType);
		m_reqNPack->AppendMember(&nd1);
	}
	CxReq* cxReq = new CxReq(callId, m_reqNPack);
	//设置返回
	AttachReturn(cxReq);
	//发起调用
	reqServer->PushReq(cxReq);
	//等待返回
	if (!m_pCxReturn->Pend(200)) {
		return 1;
	}
	//构造读返回值
	if (isRead) {
		DWORD npLen = m_resNdata->Length();
		if (npLen > 4) {
			Ndata2ByteBuf(buf, bufLen, m_resNdata);
		}
	}
	return 0;
}

void McuModbusSlaver::AttachReturn(CxReq* cxReq) {
	cxReq->AttachSyncReturn(m_pCxReturn);
	m_resNdata->SetNull();
	m_returnData->m_error = 0x0000;
	cxReq->AttachReturnData(m_returnData);
}

uint8_t McuModbusSlaver::ByteBuf2Ndata(const uint8_t* buf, uint16_t bufLen, Ndata* ndata, uint16_t dataType) {
	if (bufLen == 2) {
		ndata->SetWord(MB_MEG2(buf[0], buf[1]));
		return 0;
	}
	if (bufLen == 4) {
		DWORD v = MB_MEG4(buf[0], buf[1], buf[2], buf[3]);
	  if(dataType==DVB_TYPE){
			 ndata->SetDvb(v);
		}else{
		   ndata->SetDword(v);
		}
		return 0;
	}
	ndata->SetDataBody(STRUCT_TYPE, buf, bufLen);
	return 0;
}

uint8_t McuModbusSlaver::Ndata2ByteBuf(uint8_t* buf, uint16_t bufLen, Ndata* ndata) {
	WORD dataType = ndata->DataType();
	if (dataType == W_TYPE) {
		uint8_t* v = (uint8_t*)ndata->DataBody();
		buf[0] = v[1];
		buf[1] = v[0];
		return 0;
	}
	if (dataType == DW_TYPE || dataType == DVB_TYPE) {
		uint8_t* v = (uint8_t*)ndata->DataBody();
		for (int i = 0; i < 4; i++)
		{
			buf[i] = v[3 - i];
		}
		return 0;
	}
	if (dataType == STR_TYPE) {
		uint8_t* v = (uint8_t*)ndata->DataBody();
		memcpy_s(buf, bufLen, v, bufLen);
		return 0;
	}
	uint8_t* v = (uint8_t*)ndata->DataBody();
	uint8_t dataSize = ndata->DataSize();
	if (dataSize == bufLen) {
		memcpy_s(buf, bufLen, v, bufLen);
	}
	return 0;
}




uint8_t McuModbusSlaver::Fun06() {
	if (ReadOrWrite(0, m_startAddress, &m_reqBuffer[4], 2) > 0) {
		return 1;
	}
	if (IsNeedReply()) {
		m_pCommDriver->Send(m_reqBuffer, m_reqBufferLen);
	}
	return 0;
}

uint8_t McuModbusSlaver::Fun16() {
	uint8_t inx = 0;
	//设备地址
	m_resBuffer[inx++] = m_reqBuffer[0];
	//功能码
	m_resBuffer[inx++] = m_reqBuffer[1];
	//起始地址
	m_resBuffer[inx++] = m_reqBuffer[2];
	m_resBuffer[inx++] = m_reqBuffer[3];
	//寄存器数
	m_resBuffer[inx++] = m_reqBuffer[4];
	m_resBuffer[inx++] = m_reqBuffer[5];

	if (ReadOrWrite(0, m_startAddress, &m_reqBuffer[7], m_reqBuffer[6])) {
		return 1;
	}
	uint16_t crc = McuModbusCrc(m_resBuffer, inx);
	m_resBuffer[inx++] = crc >> 8;
	m_resBuffer[inx++] = crc & 0xff;
	if (IsNeedReply()) {
		m_pCommDriver->Send(m_resBuffer, inx);
	}
	return 0;
}

uint8_t McuModbusSlaver::Fun03() {
	uint8_t inx = 0;
	m_resBuffer[inx++] = m_reqBuffer[0];
	m_resBuffer[inx++] = m_reqBuffer[1];
	m_resBuffer[inx++] = m_byteLen;
	if (ReadOrWrite(1, m_startAddress, &m_resBuffer[inx], m_byteLen)) {
		return 1;
	}
	inx = inx + m_byteLen;
	uint16_t crc = McuModbusCrc(m_resBuffer, inx);
	m_resBuffer[inx++] = crc >> 8;
	m_resBuffer[inx++] = crc & 0xff;
	if (IsNeedReply()) {
		m_pCommDriver->Send(m_resBuffer, inx);
	}
	return 0;
}



uint8_t McuModbusSlaver::Fun100() {
	uint8_t inx = 0;
	m_resBuffer[inx++] = m_reqBuffer[0];
	m_resBuffer[inx++] = m_reqBuffer[1];
	m_resBuffer[inx++] = m_reqBuffer[2];
	m_resBuffer[inx++] = m_reqBuffer[3];
	m_resBuffer[inx++] = m_reqBuffer[4];
	m_resBuffer[inx++] = m_reqBuffer[5];
	WORD memId = 0;
	WORD memDataType = 0;
	WORD ddaId = MB_MEG2(m_reqBuffer[4], m_reqBuffer[5]);
	//找实例
	IReqProcessor* reqServer = LocateReqServerAndMemberId(ddaId, &memId,&memDataType);
	if (reqServer == NULL) {
		return 1;
	}
	WORD callId = MB_MEG2(m_reqBuffer[2], m_reqBuffer[3]);
	//构造请求参数
	m_reqNPack->Reset();
	if (m_reqBufferLen > 8) {
		m_reqNPack->ImportN(&m_reqBuffer[6]);
	}
	CxReq* cxReq = new CxReq(callId, m_reqNPack);
	//设置返回
	AttachReturn(cxReq);
	//发起调用
	reqServer->PushReq(cxReq);
	//等待返回
	if (m_pCxReturn->Pend(200)) {
		DWORD npLen = m_resNdata->Length();
		if (npLen >= 4 && m_returnData->m_error==0) {
			memcpy_s(&m_resBuffer[inx], npLen, m_resNdata->Buffer(), npLen);
			inx = inx + npLen;
		}
	}
	uint16_t crc = McuModbusCrc(m_resBuffer, inx);
	m_resBuffer[inx++] = crc >> 8;
	m_resBuffer[inx++] = crc & 0xff;
	if (IsNeedReply()) {
		m_pCommDriver->Send(m_resBuffer, inx);
	}
	return 0;
}


uint8_t McuModbusSlaver::Fun100ForDiscover() {
    uint8_t inx = 0;
	m_resBuffer[inx++] = m_reqBuffer[0];
	m_resBuffer[inx++] = m_reqBuffer[1];
	m_resBuffer[inx++] = m_reqBuffer[2];
	m_resBuffer[inx++] = m_reqBuffer[3];
	m_resBuffer[inx++] = m_reqBuffer[4];
	m_resBuffer[inx++] = m_reqBuffer[5];
	WORD ddaId = MB_MEG2(m_reqBuffer[4], m_reqBuffer[5]);
	if(ddaId!=0){
	  return 1;
	}
	WORD mbInfo[2];
	mbInfo[0]=m_slaveAddr;
	mbInfo[1]=m_teamCount;
	m_resNdata->SetDataBody(WA_TYPE,mbInfo,sizeof(mbInfo));
	DWORD npLen = m_resNdata->Length();
	memcpy_s(&m_resBuffer[inx], npLen, m_resNdata->Buffer(), npLen);
	inx = inx + npLen;
	uint16_t crc = McuModbusCrc(m_resBuffer, inx);
	m_resBuffer[inx++] = crc >> 8;
	m_resBuffer[inx++] = crc & 0xff;
	if (IsNeedReply()) {
		m_pCommDriver->Send(m_resBuffer, inx);
	}
	return 0;
}

/// <summary>
///检查是否需要执行
/// </summary>
/// <param name="reqSlaveAddr">
/// 0:   广播地址,所有卡执行但不回复
/// 247: 通用地址,所有卡执行且回复
/// 246: 发现地址,主卡执行且回复,子卡忽略
/// </param>
/// <returns></returns>
BOOL McuModbusSlaver::IsNeedExec(uint8_t reqSlaveAddr) {
	//这3个地址,所有卡都要执行
	if (reqSlaveAddr == m_slaveAddr || reqSlaveAddr == MODBUS_SLAVE_ADDR_BROADCAST || reqSlaveAddr == MODBUS_SLAVE_ADDR_GENERAL) {
		return TRUE;
	}
	//主卡匹配主卡地址
	if (m_isLeader && reqSlaveAddr == MODBUS_SLAVE_ADDR_DISCOVER) {
		return TRUE;
	}
	return FALSE;
}

/// <summary>
/// 检查是否需要响应
/// </summary>
BOOL McuModbusSlaver::IsNeedReply() {
	uint8_t reqSlaveAddr = m_reqBuffer[0];
	//自己地址或通用地址
	if (reqSlaveAddr == m_slaveAddr || reqSlaveAddr == MODBUS_SLAVE_ADDR_GENERAL) {
		return TRUE;
	}
	//主卡地址
	if (m_isLeader && reqSlaveAddr == MODBUS_SLAVE_ADDR_DISCOVER) {
		return TRUE;
	}
	return FALSE;
}






WORD McuModbusSlaver::Import(uint8_t* buf, uint16_t bufLen) {
	//至少8个字节
	if (bufLen < 8) {
		return 0;
	}
	//需要忽略的地址
	if (!IsNeedExec(buf[0])) {
		m_pCommDriver->Receive(m_reqBuffer, bufLen);
		return 0;
	}
	//长度检查
	switch (buf[1]) {
	   case MODBUS_FUN_CODE_03: 
		 case MODBUS_FUN_CODE_06: {
			 if (bufLen != 8) {
				  return 0;
			 }
			 break;
		 }
		 case MODBUS_FUN_CODE_16: {
			 if (bufLen != buf[6]+9) {
				 return 0;
			 }
			 break;
		 }
		 case MODBUS_FUN_CODE_100: {
			 //有参的rpc调用检查长度
			 if (bufLen > 8) {
				 int packLen = MB_MEG2(buf[7], buf[6]);
				 if (bufLen != packLen + 8) {
					 return 0;
				 }
			 }
			 break;
		 }
		 default: {
			 return 0;
		 }
	}
	if (McuModbusCrc(buf, bufLen)!=0) {
		return 0;
	}
	m_reqBufferLen = m_pCommDriver->Receive(m_reqBuffer, bufLen);
	return m_reqBufferLen;
}


void McuModbusSlaver::Exec()
{
	uint8_t  reqSlaveAddr = m_reqBuffer[0];
	uint8_t  errCode = MODBUS_ERR_CODE_SUCCESS;
	//起始地址
	m_startAddress = MB_MEG2(m_reqBuffer[2], m_reqBuffer[3]);
	//读写的字节数
	m_byteLen = MB_MEG2(m_reqBuffer[4], m_reqBuffer[5]) * 2;
	//读取数量限制
	if (m_reqBuffer[1] == 0x03 && m_byteLen > 128) {
		errCode = MODBUS_ERR_CODE_ILLEGAL_DATA_ADDRESS;
	}
	//执行
	if (errCode == MODBUS_ERR_CODE_SUCCESS) {
		uint8_t execRessult=0;
		switch (m_reqBuffer[1]) {
				//读保持寄存器
				case MODBUS_FUN_CODE_03:  execRessult = Fun03(); break;
				//写单个保持寄存器
				case MODBUS_FUN_CODE_06:  execRessult = Fun06(); break;
				//写多个保持寄存器
				case MODBUS_FUN_CODE_16:  execRessult = Fun16(); break;
				//Rpc与发现
				case MODBUS_FUN_CODE_100: 
					     if(reqSlaveAddr== MODBUS_SLAVE_ADDR_DISCOVER){
							   execRessult = Fun100ForDiscover(); 
						 }else{
						      execRessult  = Fun100(); 
						 }
				break;
				default: {
					errCode = MODBUS_ERR_CODE_ILLEGAL_FUNCTION_CODE;
				}
		}
		if (execRessult != 0) {
			errCode = MODBUS_ERR_CODE_SUB_STATION_EQUIPMENT_ERROR;
		}
	}
	//异常响应
	if (errCode != MODBUS_ERR_CODE_SUCCESS && IsNeedReply()) {
		uint8_t inx = 0;
		m_resBuffer[inx++] = m_reqBuffer[0];
		m_resBuffer[inx++] = 0x80 + m_reqBuffer[1];
		m_resBuffer[inx++] = errCode;
		uint16_t crc = McuModbusCrc(m_resBuffer, inx);
		m_resBuffer[inx++] = crc >> 8;
		m_resBuffer[inx++] = crc & 0xff;
		m_pCommDriver->Send(m_resBuffer, inx);
	}
	return;
}
